package utils

import (
	"context"
	"log"
	"time"

	"go.etcd.io/etcd/api/v3/mvccpb"
	clientv3 "go.etcd.io/etcd/client/v3"
	"gopkg.in/yaml.v2"
)

/*
 +----------------------------------------------------------------------
 + Title        : EtcdConfigCenter
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2022-01-06
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : Etcd 配置中心
 +				: 文档地址:
 +				: 插件:
 +----------------------------------------------------------------------
*/
// 定义ETCD配置中心结构体
type EtcdConfigCenter struct {
	client     *clientv3.Client
	watchedKey string
}

/**
 * 创建ETCD配置中心
 *
 * @param []string endpoints ------------------------------------------必传
 * @param string configName -------------------------------------------必传
 * @return *EtcdConfigCenter, error
 * @author huwl
 */
func NewEtcdConfigCenter(endpoints []string, username, password, configName string) (*EtcdConfigCenter, error) {
	// 创建 etcd 连接
	client, err := clientv3.New(clientv3.Config{
		Endpoints:   endpoints,
		Username:    username,
		Password:    password,
		DialTimeout: 5 * time.Second,
	})

	if err != nil {
		return nil, err
	}

	return &EtcdConfigCenter{
		client:     client,
		watchedKey: configName,
	}, nil
}

/**
 * 获取配置数据
 *
 * @param any ConfigStruct --------------------------------------------必传
 * @author huwl
 */
func (cc *EtcdConfigCenter) GetConfigData(ConfigStruct any) {
	resp, err := cc.client.Get(context.Background(), cc.watchedKey, clientv3.WithPrefix())
	if err != nil {
		log.Fatalf("Failed to get config: %v", err)
	}

	for i := range resp.Kvs {
		yaml.Unmarshal(resp.Kvs[i].Value, ConfigStruct)
	}
}

/**
 * 监控配置
 *
 * @param string configName -------------------------------------------必传
 * @param any ConfigStruct --------------------------------------------必传
 * @author huwl
 */
func (cc *EtcdConfigCenter) WatchConfig(configName string, ConfigStruct any) {
	go func() {
		watchChan := cc.client.Watch(context.Background(), cc.watchedKey, clientv3.WithPrefix())
		for v := range watchChan {
			for _, ev := range v.Events {
				switch ev.Type {
				case mvccpb.PUT:
					yaml.Unmarshal(ev.Kv.Value, ConfigStruct)
					log.Printf("etcd watch config data: %v", ConfigStruct)
					// 在这里更新配置，比如重新初始化数据库连接等
					switch configName {
					case MySqlConfigCenter:
						// 重新初始化 mysql 连接
						InitMysqlDatabaseConnect()
					case RedisConfigCenter:
						ResetRedisInstance()

					}
				case mvccpb.DELETE:

				}
			}
		}
	}()
}
